home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / graphics / gnuplot / contrib / campbell / cpr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-27  |  26.6 KB  |  992 lines

  1. /*      if UNIX:        cc -O cpr.c
  2.  *      if MSDOS:       cc -O -DMSDOS cpr.c
  3.  *      if VMS:         define sys sys$library; cc cpr.c
  4.  *
  5.  *      This program prints the files named in its argument list, preceding
  6.  *      the output with a table of contents. Each file is assumed to be C
  7.  *      source code (but doesn't have to be) in that the program searches
  8.  *      for the beginning and end of functions. Function names are added to
  9.  *      the table of contents, provided the name starts at the beginning of
  10.  *      a line. The function name in the output is bolded.
  11.  *
  12.  *      By default blank space is inserted after every closing '}'
  13.  *      character. Thus functions and structure declarations are nicely
  14.  *      isolated in the output. The only drawback to this is that structure
  15.  *      initialization tables sometimes produce lots of white space.
  16.  *      The "-r" option removes this space, or changes it to the indicated
  17.  *      length.
  18.  *
  19.  *      The option "-l" indicates that the following argument is to be
  20.  *      the page length used for output (changing the page length hasn't been
  21.  *      tested much).
  22.  *
  23.  *      The option "-s" indicates that the table of contents should be sorted
  24.  *      by function name within each file.
  25.  *
  26.  *      The option "-n" indicates that output lines should be numbered with
  27.  *      the corresponding line number from the input file.
  28.  *
  29.  *      The option "-p" indicates what proportion of the page in steps of 16
  30.  *      should be used for deciding if a new function needs a new page.
  31.  *      That is -p12 (the default) indicates that if a function starts
  32.  *      within the top 12/16 (3/4) of the page then do it, otherwise put it
  33.  *      on a new page.  Thus the higher the number (upto 16) the closer to
  34.  *      the bottom of the page will functions be started. -p0 says put each
  35.  *      func on a new page.
  36.  *
  37.  *      Try it! You'll like it. (I call it cpr.c)
  38.  *
  39.  *      Written by:
  40.  *              Paul Breslin
  41.  *              Human Computing Resources Corp.
  42.  *              10 St. Mary St.
  43.  *              Toronto, Ontario
  44.  *              Canada, M4Y 1P9
  45.  *
  46.  *              -- ...!decvax!utcsrgv!hcr!phb
  47.  *
  48.  *      Sorting and standard input reading from:
  49.  *              Rick Wise, CALCULON Corp., Rockville, MD.
  50.  *              -- ...!decvax!harpo!seismo!rlgvax!cvl!umcp-cs!cal-unix!wise
  51.  *
  52.  *      File modified time,
  53.  *      numbered output,
  54.  *      optional white space,
  55.  *      improved function start tests from:
  56.  *              David Wasley, U.C.Berkeley
  57.  *              -- ...!ucbvax!topaz.dlw
  58.  *      Modified the -r to leave variable amounts of space
  59.  *              Patrick Powell, U. Waterloo
  60.  *
  61.  *      Changed handling of form feeds to start a new page AND print heading:
  62.  *              Terry Doner, U of Waterloo
  63.  *
  64.  *      Fixed up to locate more functions, and added -p option
  65.  *              Dennis Vadura, U of Waterloo
  66.  *              dvadura@watdragon.waterloo.edu (Dennis Vadura)
  67.  *
  68.  *              It will find things like  struct foo *f()...
  69.  *              but not things like     int
  70.  *                                      f
  71.  *                                      ()...
  72.  *              ie. the constraint is that the () must appear on the same line
  73.  *              as the function name.
  74.  *
  75.  *  Clean up a bit for 80286 machines (lints a bit cleaner, too)
  76.  *      Dan Frank, Prairie Computing
  77.  *
  78.  *  Fixed a whole bunch of stuff and added lots of new flags.
  79.  *      -S       sort and be case insensitive.
  80.  *      -N       start numbering pages at 1 for each new file
  81.  *      -T title cat the file title before the table of contents.
  82.  *      -C       print only the table of contents
  83.  *      -c       only try to look for function names in files whose suffix ends
  84.  *               in .c
  85.  *      -f file  to handle file containing list of files to print. (for MSDOS)
  86.  *      Dennis Vadura
  87.  *
  88.  *  Added VMS and Language support, -h, -o options, reorganized bolding, and
  89.  *  shortened long names (so page numbers aren't lost).  Also put in getopt().
  90.  *  Oh yeah, expanded tabs (which wasn't what -t originally meant).
  91.  *      -h str   String to put at the top of each page instead of file name.
  92.  *      -o off   Number of spaces to put in front of each line of code.
  93.  *      -a lang  Assume the following language.  Default is AUTO (use file
  94.  *               name suffix to guess language).  NONE is allowed to mean
  95.  *               don't look for function names at all.
  96.  *      -cC      Dennis Vadura's -c option is thus generalized and removed.
  97.  *               -C becomes -c (VMS requires quotes around uppercase options,
  98.  *               so where possible use lower case...)  New -C added to override
  99.  *               supression of table of contents for small output jobs.  (NONE
  100.  *               means no table of content entries, hence none printed.)
  101.  *
  102.  *               Adding a language involves (at least):
  103.  *               1) Add to enum langs.
  104.  *               2) Add recognition of language keyword (FORTRAN) to getopt().
  105.  *               3) Add reference in man page and in Usage() function.
  106.  *               4) Add recognition to Scan() for end of functions.
  107.  *               5) Build a LooksLikeXXXX() to call inside LooksLikeFunction().
  108.  *               6) Add suffix recognition to WhichLanguage().
  109.  *               Then search everywhere for Language and see if you've missed
  110.  *               anything; if so edit this comment (smile).
  111.  *
  112.  *      John Campbell (...!arizona!naucse!jdc  or  CAMPBELL@NAUVAX)
  113.  *
  114.  *  Dennis Vadura:
  115.  *    Added a few options, -i, to ignore form-feed chars in original
  116.  *    source, -O to force output for two-up printing (this option
  117.  *    affects both table of contents and the file listing output and
  118.  *    handles the -T option correctly), added -F to print only file
  119.  *    listings.
  120.  *
  121.  *    renamed John Campbell's -h str to -H str so that -h can be used as
  122.  *    help (ie. the -? gets you in trouble in most shells and you have to
  123.  *    escape it etc.)
  124.  *
  125.  *    Cleaned up printing of help message.
  126.  *
  127.  *    Oh, what the hell, took the a2ps.c postscript converter and added the
  128.  *    capability to produce a postscript output file.  Seems Really nice,
  129.  *    might need a bit of tweeking but hey, I don't have hours to spend.
  130.  *    It's good enough for me :-)
  131.  *
  132.  *    To do this I hacked the code quite a bit, re-organized some functions
  133.  *    put in new ones, and made all output go through a common set of
  134.  *    routines.  I also changed cpr's output format to match that of the
  135.  *    postscript code.
  136.  *
  137.  *    I took the a2ps postscript code and embeded it into cpr, I prefered
  138.  *    this over keeping it as an included separate file, in an effort to
  139.  *    keep cpr self contained.
  140.  *
  141.  *    Bumped the version # to 2.5.
  142.  */
  143. char *version = "2.5"; /* Just a guess--never had one before. */
  144.  
  145. #include <sys/types.h>
  146. #include <sys/stat.h>
  147. #include <stdio.h>
  148. #include <ctype.h>
  149. #include <signal.h>
  150. #include <string.h>
  151. #ifdef __TURBOC__
  152. #define MSDOS 1
  153. #endif
  154. #ifndef VMS
  155. extern int errno; /* system error number */
  156. extern char *sys_errlist[]; /* error message */
  157. #define CANT_OPEN(p1) \
  158.    fprintf(stderr,"%s: Can't open file '%s': %s\n", \
  159.            ProgName, p1, sys_errlist[errno] )
  160. #else
  161. #include <perror.h>
  162. #define CANT_OPEN(p1) \
  163.    if (errno == EVMSERR) {\
  164.       fprintf (stderr, "Can't open %s\n", p1);\
  165.       LIB$STOP (vaxc$errno);\
  166.    }\
  167.    fprintf(stderr,"%s: Can't open file '%s': %s\n",\
  168.            ProgName, p1, sys_errlist[errno] )
  169. #endif
  170. #if MSDOS || VMS
  171. #include "getopt.c"
  172. #endif
  173.  
  174. extern char *malloc() ; /* important for 8086-like systems */
  175.  
  176. #define FALSE        0
  177. #define TRUE        1
  178.  
  179. #define TOC_SIZE        4096
  180. #define MAXLINE          256
  181.  
  182. #define NEWFILE         1
  183. #define NEWFUNCTION     2
  184.  
  185. #define SMALLC          8   /* Too few contents for a table of contents. */
  186. #define SMALLP         10   /* Too few pages for a table of contents. */
  187.  
  188. FILE *File, *FList = NULL;
  189.  
  190. int Braces; /* Keeps track of brace depth       */
  191. int LineNumber; /* Count output lines           */
  192. int PageNumber = 1; /* You figure this one out  */
  193. int ActualPageCount = 0; /* Actual number of pages printed */
  194. int PageLength = 66; /* -l <len> Normal paper length    */
  195. int PagePart = 12; /* Decision on paging for new fn*/
  196. int PageEnd; /* Accounts for space at bottom    */
  197. int SawFunction;
  198. int InComment;
  199. int InString;
  200. int ResetPage=0;
  201. int ContentsOnly=0;
  202. int FilesOnly=0;
  203. int AlwaysContents=0;
  204. int CaseInsensitive=0;
  205. int StartOdd=0;
  206. int IgnoreFF=0;
  207.  
  208. long FileLineNumber; /* Input file line number  */
  209.  
  210. char *TitleFile = NULL;
  211. char *ProgName;
  212. char Today[30];
  213. char *Name; /* Current file name                */
  214. char *Header = NULL;  /* User's header (-h "header") */
  215. char *Title  = NULL;
  216.  
  217. char *FileDate; /* Last modified time of file        */
  218. char FunctionName[MAXLINE+1];
  219.  
  220. char SortFlag; /* -s == sort table of contents  */
  221. char NumberFlag; /* -n == output line numbers   */
  222. int OffsetValue = 0; /* -o <number> Offset each line (of code) N spaces */
  223. int Space_to_leave = 5; /* -r<number> space to leave    */
  224. int TabWidth = 8; /* -t <number> width of tabs  */
  225.  
  226. /* Language types */
  227. enum langs {NONE, AUTO, C, FORTRAN, ICON, LISP}
  228.    Language = AUTO;
  229. /*
  230.    Printer types (Would you believe I have to support a printer that can't
  231.    backspace?  Geesh!)
  232. */
  233. #define DUMB       0
  234. #define BACKSPACE  1       /* Probably most reasonable default. */
  235. #define ANSI       2       /* Just uses ansi escape sequences to bold */
  236. #define LN03       3       /* For now same as ANSI--later smaller print! */
  237. #define NECP5200   4       /* NEC 24 pin printer--in HS mode. */
  238. #define POSTSCRIPT 5       /* print on a postscript printer */
  239. int Printer = BACKSPACE;   /* Choose your default. */
  240.  
  241. extern char *optarg;
  242. extern int optind, opterr;
  243.  
  244. static char *Toc[TOC_SIZE];
  245. static int TocPages[TOC_SIZE];
  246. static int TocCount;
  247.  
  248.  
  249. #ifdef VMS
  250. #include <errno.h>  /* Watch out for EVMSERR (special 65535 errno) */
  251. #define unlink delete
  252. #define toupper _toupper  /* Faster to use macro version. */
  253. /*
  254.    Local (NAU) support for redirection, other VMS sites can leave this out,
  255.    but then they can't use wild cards (*.c), or redirection (>cpr.out).
  256.    If you are a VMS site and want this contact CAMPBELL@NAUVAX.bitnet.
  257. */
  258. #include "nau_utils:redexp.vms"
  259. #endif
  260. main(argc, argv)
  261. char **argv;
  262. {
  263.    register int i;
  264.    char *ctime();
  265.    char *pname=NULL;
  266.    char *s;
  267.    time_t thetime, time();
  268.    int c;
  269.    enum langs start_lang, WhichLanguage();
  270.  
  271.    FileDate = (char *)malloc(100);
  272.    ProgName = argv[0];
  273.    thetime = time((time_t *)0);
  274.    strcpy(Today,ctime(&thetime));
  275.    if( (s = strchr(Today,'\n')) != NULL ) *s = '\0';
  276.  
  277. /* Parse options. */
  278.    while ((c = getopt (argc, argv, "cCFhisSnNOa:f:H:t:T:l:o:r:p:P:")) != EOF) {
  279.       switch (c) {
  280.       case 'a':                    /* Assume a language ('C', FORTRAN,...) */
  281.          c = *optarg;
  282.          switch (c) {
  283.          case 'C':
  284.          case 'c':
  285.             Language = C;
  286.          break;
  287.          case 'F':
  288.          case 'f':
  289.             Language = FORTRAN;
  290.          break;
  291.          case 'I':
  292.          case 'i':
  293.             Language = ICON;
  294.          break;
  295.          case 'L':
  296.          case 'l':
  297.             Language = LISP;
  298.          break;
  299.          case 'N':
  300.          case 'n':
  301.             Language = NONE;
  302.          break;
  303.          case 'A':
  304.          case 'a':
  305.             Language = AUTO;
  306.          break;
  307.          default:
  308.             fprintf (stderr, "Unknown or unsupported language\n");
  309.         exit(1);
  310.          }
  311.          break;
  312.  
  313.       case 'F':
  314.      ++FilesOnly;
  315.      break;
  316.  
  317.       case 'O':
  318.      ++StartOdd;
  319.      break;
  320.  
  321.       case 'i':
  322.      ++IgnoreFF;
  323.      break;
  324.  
  325.       case 'f':
  326.          if (*optarg == '-') {
  327.             FList = stdin;
  328.          }
  329.          else if ((FList = fopen (optarg, "r")) == NULL) {
  330.             fprintf (stderr, "Can't open file names list %s\n", optarg);
  331.         exit(1);
  332.          }
  333.          break;
  334.       case 'H':       /* User's header */
  335.          Header = optarg;
  336.          break;
  337.  
  338.       case 't':
  339.          TabWidth = atoi(optarg);
  340.          if( TabWidth < 0 )
  341.             TabWidth = 0;
  342.          break;
  343.  
  344.       case 'T':
  345.          TitleFile = optarg;
  346.          break;
  347.  
  348.       case 'l':
  349.          PageLength = atoi(optarg);
  350.          if( PageLength < 10) PageLength = 10;
  351.          break;
  352.  
  353.       case 'S':
  354.          ++CaseInsensitive;
  355.       case 's':
  356.          ++SortFlag;
  357.          break;
  358.  
  359.       case 'C':
  360.          ++AlwaysContents;
  361.          break;
  362.  
  363.       case 'c':
  364.          ++ContentsOnly;
  365.          break;
  366.  
  367.       case 'n':
  368.          ++NumberFlag;
  369.          break;
  370.  
  371.       case 'N':
  372.          ++ResetPage;
  373.          break;
  374.  
  375.       case 'o':            /* Offset code by <number> */
  376.          OffsetValue = atoi(optarg);
  377.          if (OffsetValue <= 0) {
  378.             fprintf (stderr, "Offset must be a positive integer only\n");
  379.         exit(1);
  380.          }
  381.          if (OffsetValue > 32) {
  382.             fprintf (stderr, "Offset must be less than 32\n");
  383.         exit(1);
  384.          }
  385.          break;
  386.  
  387.       case 'r':
  388.       /* It's ok to have a '0' from the "?" here... */
  389.          Space_to_leave = atoi(optarg);
  390.          break;
  391.  
  392.       case 'P':
  393.          pname = optarg;  /* Override printer default or CPRINTER environ */
  394.          break;
  395.  
  396.       case 'p':
  397.          PagePart = atoi(optarg);
  398.          PagePart = PagePart <= 16 ? PagePart : 16;
  399.          break;
  400.  
  401.       case 'h':
  402.       default:
  403.          Usage();
  404.          break;
  405.       }
  406.    }
  407.  
  408.    start_lang = Language;
  409.  
  410.    Init (pname);
  411.    StartTempFile();
  412.  
  413.    i = optind;
  414.  
  415.    if( FList == NULL && i == argc )
  416.    { /* no file names */
  417.       File = stdin;
  418.       Name = "Standard Input";
  419.       if (start_lang == AUTO) Language = C;
  420.       List();
  421.    }
  422.  
  423.    if( FList != NULL)
  424.    {
  425.       char b[1024];
  426.  
  427.       while( fgets(b, 1024, FList) != NULL )
  428.       {
  429.          if( strlen(b) ) b[strlen(b)-1]=0;
  430.  
  431.          if( strcmp(b, "-") != 0 )
  432.          {
  433.             if( (File = fopen( Name = b, "r" )) == NULL )
  434.             {
  435.                CANT_OPEN (Name);
  436.                continue;
  437.             }
  438.             if (start_lang == AUTO) {
  439.                Language = WhichLanguage (Name);
  440.             }
  441.          }
  442.          else {
  443.             Name = "Standard Input";
  444.             if (start_lang == AUTO) Language = C;
  445.             File = stdin;
  446.          }
  447.  
  448.          List();
  449.          if( File != stdin ) fclose(File);
  450.       }
  451.    }
  452.    for(; i < argc; ++i )
  453.    {
  454.       if( strcmp(argv[i], "-") == 0 )
  455.       {
  456.          File = stdin;
  457.          Name = "Standard Input";
  458.          if (start_lang == AUTO) Language = C;
  459.          List();
  460.       }
  461.       else {
  462.          if( (File = fopen( Name = argv[i], "r" )) == NULL )
  463.          {
  464.             CANT_OPEN (Name);
  465.             continue;
  466.          }
  467.          if (start_lang == AUTO) {
  468.             Language = WhichLanguage (Name);
  469.          }
  470.          List();
  471.          if( File != stdin ) fclose(File);
  472.       }
  473.    }
  474.  
  475.    if( PageNumber > 1 || LineNumber > 0 ) BlankPage();
  476.    if( StartOdd && ((ActualPageCount % 2) != 0) ) BlankPage();
  477.  
  478.    Fini();
  479.    EndTempFile();
  480.  
  481.    if( Printer == POSTSCRIPT ) DumpPostscriptHeader();
  482.    DumpTableOfContents();
  483.    DumpTempFiles();
  484.    Done();
  485. }
  486.  
  487. Usage()
  488. {
  489.    char buf[132];
  490.    char *p;
  491.    sprintf( buf, "Usage: %s ", ProgName );
  492.  
  493.    printf("%s[-CcFhiNnOsS] [-a language] [-H header] [-l pagelen]\n", buf);
  494.    for(p=buf; *p; *p++ = ' ' );
  495.    printf("%s[-o offset] [-P printer] [-p[num]] [-r[num]] [-T title]\n", buf);
  496.    printf("%s[-t tabwidth] [[-f flist] | file...]\n\n", buf );
  497.  
  498.    puts("OPTIONS: (first group can be combined)");
  499.    puts("   -C   - Force output of table of contents" );
  500.    puts("   -c   - Print only table of contents (implies -C, overrides -F)" );
  501.    puts("   -F   - Print only file contents" );
  502.    puts("   -h   - Provide help message (you're reading it)" );
  503.    puts("   -i   - Ignore form-feeds in original source");
  504.    puts("   -N   - Number pages of each file starting at page #1" );
  505.    puts("   -n   - Number output lines of each file" );
  506.    puts("   -O   - Force new files to start at an odd numbered actual page" );
  507.    puts("   -s   - Sort TOC by function name within each file" );
  508.    puts("   -S   - Same sort as -s, but ignore case\n" );
  509.  
  510.    puts("   -a language - select language class" );
  511.    puts("   -H header   - specify personal heading" );
  512.    puts("   -l pagelen  - define new pagelength" );
  513.    puts("   -o offset   - set offset from left of page" );
  514.    puts("   -P print    - select printer class" );
  515.    puts("   -p[num]     - control function placement on page" );
  516.    puts("   -r[num]     - control function spacing on page" );
  517.    puts("   -T title    - print a title from file 'title'" );
  518.    puts("   -t tabwidth - set tabwidth" );
  519.    puts("   -f flist    - read 'flist' for list of files to print\n" );
  520.  
  521.    puts("Language choices are:  C, FORTRAN, ICON, and LISP" );
  522.    puts("Supported printers:    DUMB, BACKSPACE, ANSI, LN03, NECP5200, and POSTSCRIPT");
  523.    exit(1);
  524. }
  525.  
  526. int SaveOut;
  527. char *TempName;
  528. char *Temp2Name;
  529.  
  530. StartTempFile()
  531. {
  532.    int Done();
  533.    extern char *mktemp();
  534.  
  535.    CatchSignalsPlease(Done);
  536.  
  537.    SaveOut = dup(1);
  538. #if MSDOS | VMS
  539.    TempName = "cpr0001.tmp";
  540. #else
  541.    TempName = mktemp("/tmp/cprXXXXXX");
  542. #endif
  543.    if( freopen(TempName, "w", stdout) == NULL )
  544.    {
  545.       CANT_OPEN (TempName);
  546.       exit(1);
  547.    }
  548. }
  549.  
  550. EndTempFile()
  551. {
  552. #if MSDOS | VMS
  553.    Temp2Name = "cpr0002.tmp";
  554. #else
  555.    Temp2Name = mktemp("/tmp/cprXXXXXX");
  556. #endif
  557.    if( freopen(Temp2Name, "w", stdout) == NULL )
  558.    {
  559.       CANT_OPEN (Temp2Name);
  560.       exit(1);
  561.    }
  562. }
  563.  
  564. DumpTempFiles()
  565. {
  566. #if (MSDOS | VMS)
  567.    FILE *f;
  568.    char b[256];
  569. #endif
  570.    register int pid, w;
  571.  
  572.    fclose(stdout);
  573.  
  574. #if !(MSDOS || VMS)
  575.    dup(SaveOut);
  576.    while( (pid = fork()) < 0 ) sleep(1);
  577.    if( pid )
  578.       while ((w = wait((int *)0)) != pid && w != -1);
  579.    else
  580.       {
  581.       CatchSignalsPlease(SIG_DFL);
  582.  
  583.       if( ContentsOnly )
  584.          execl( "/bin/cat", "cat", Temp2Name, (char *)0 );
  585.       else {
  586.       /*
  587.          Ok, use a heuristic to see if it is worth putting out the
  588.          table of contents.  They seem useless and annoying when cpr
  589.          is just printing a small job.  Heuristic: more than 10 entries
  590.          in the table of contents AND more than 8 pages of output.
  591.       */
  592.          if( !FilesOnly &&  (AlwaysContents ||
  593.                       (TocCount > SMALLC && TocPages[TocCount-1] > SMALLP)))
  594.            execl( "/bin/cat", "cat", Temp2Name, TempName, (char *)0 );
  595.          else
  596.             execl( "/bin/cat", "cat", TempName, (char *)0 );
  597.       }
  598.       fprintf(stderr, "%s: exec of /bin/cat failed: %s\n", ProgName,
  599.       sys_errlist[errno]);
  600.       exit(1);
  601.    }
  602. #else
  603.    CatchSignalsPlease(SIG_DFL);
  604.    /*
  605.       Use a heuristic to see if it is worth putting out the table of contents.
  606.       They seem useless and annoying when cpr is printing a small job.
  607.       Heuristic: > 10 entries in the table of contents or > 8 pages of output.
  608.    */
  609.    if( !FilesOnly && (AlwaysContents || (TocCount > SMALLC &&
  610.  TocPages[TocCount-1] > SMALLP))) {
  611.       if( (f=fopen(Temp2Name,"r")) == NULL ) {
  612.          CANT_OPEN (Temp2Name);
  613.       }
  614.       else
  615.       {
  616.          while( fgets(b, MAXLINE, f) != NULL )
  617.             write(SaveOut,b,strlen(b));
  618.  
  619.          fclose(f);
  620.       }
  621.    }
  622.    if( !ContentsOnly )
  623.       if( (f=fopen(TempName,"r")) == NULL ) {
  624.       CANT_OPEN (TempName);
  625.       }
  626.       else
  627.       {
  628.          while( fgets(b, MAXLINE, f) != NULL )
  629.             write(SaveOut,b,strlen(b));
  630.  
  631.          fclose(f);
  632.       }
  633. #endif
  634. }
  635.  
  636. Done()
  637. {
  638.    CatchSignalsPlease(SIG_DFL);
  639.  
  640.    fclose( stdout );
  641.    if( TempName ) unlink( TempName );
  642.    if( Temp2Name ) unlink( Temp2Name );
  643.  
  644.    exit(0);
  645. }
  646.  
  647. CatchSignalsPlease(action)
  648. #ifdef __TURBOC__
  649. void (*action)();
  650. #else
  651. int (*action)();
  652. #endif
  653. {
  654.    if( signal(SIGINT, SIG_IGN) != SIG_IGN ) signal(SIGINT, action);
  655. #ifndef MSDOS
  656.    if( signal(SIGQUIT, SIG_IGN) != SIG_IGN ) signal(SIGQUIT, action);
  657.    if( signal(SIGHUP, SIG_IGN) != SIG_IGN ) signal(SIGHUP, action);
  658. #endif
  659. }
  660.  
  661. List()
  662. {
  663.    register int bp;
  664.    register char *bufp;
  665.    char buffer[MAXLINE];
  666.  
  667.    NewFile(0);
  668.    bp = Braces = 0;
  669.    InString = InComment = 0; /* reset for new file -DV */
  670.  
  671.    if (Language == C)
  672.       SawFunction = 0;
  673.    else if (Language == FORTRAN)
  674.       SawFunction = 1;  /* Put space after main program END card */
  675.    else if (Language == NONE)
  676.       Braces = 1;       /* Don't even call LooksLikeFunction */
  677.  
  678.    bufp = buffer;
  679.    while( fgets(bufp, MAXLINE, File) != NULL )
  680.    {
  681.       ++FileLineNumber;
  682.       if( bp ) NewFunction();
  683.  
  684.       if( ++LineNumber >= PageEnd ) NewPage();
  685.  
  686.       if( bufp[0] == '\f'
  687.          && bufp[1] == '\n'
  688.          && bufp[2] == '\0' )
  689.       {
  690.      if( !IgnoreFF )
  691.         NewPage(); /* was strcpy(bufp, "^L\n");*/
  692.          continue;
  693.       }
  694.  
  695.       if( (Braces == 0) && LooksLikeFunction(bufp) )
  696.          AddToTableOfContents(NEWFUNCTION);
  697.       else
  698.          PutString(buffer, -1, NumberFlag, 1);
  699.  
  700.       if (Language != NONE)
  701.          bp = Scan(buffer);
  702.    }
  703. }
  704.  
  705. Scan(l)
  706. register char *l;
  707. {
  708.    extern char *EndComment();
  709.    extern char *EndString();
  710.    register char c;
  711.    int bp, offset;
  712.    char *save;
  713.  
  714.    bp = 0;
  715.    switch (Language) {
  716.    case C:
  717.       for( save = l; c = *l; ++l )
  718.          if( InComment )
  719.             l = EndComment(l);
  720.          else if( InString )
  721.             l = EndString(l);
  722.          else
  723.             switch(c)
  724.             {
  725.             case '{':
  726.                ++Braces;
  727.                break;
  728.  
  729.             case '}':
  730.                if( --Braces == 0 )
  731.                      bp = 1;
  732.                break;
  733.  
  734.             case '\'':
  735.                for( ++l; *l && *l != '\''; ++l )
  736.                   if( *l == '\\' && *(l+1) ) ++l;
  737.                break;
  738.  
  739.             case '"':
  740.                InString = 1;
  741.                break;
  742.  
  743.             case '/':
  744.                if( *(l+1) == '*' )
  745.                {
  746.                   InComment = 1;
  747.                   ++l;
  748.                }
  749.                break;
  750.             }
  751.    break;
  752.    case FORTRAN:
  753.    /* Just check for an END card to indicate the routine is over... */
  754.       save = l;
  755.       while (isdigit(*l)) ++l;  /* Skip over any line statements. */
  756.       while (*l && (*l == ' ' || *l == '\t')) ++l;  /* Get to non-blank */
  757.    /* Icon really should only compare against lower case here. */
  758.       if (save != l && (offset = Compare (l, "END"))) {
  759.       /*
  760.          Check to make sure it isn't an ENDIF or some other variable name
  761.          (Unfortunately, build in a VMS ! comment checker here...)
  762.       */
  763.          l += offset;
  764.          if (*l == '\n' || *l == '!') {
  765.             Braces = 0;
  766.             bp = 1;
  767.          }
  768.       }
  769.    break;
  770.    case ICON:
  771.    /* Just check for an end keyword to indicate the routine is over... */
  772.       save = l;
  773.       while (*l && (*l == ' ' || *l == '\t')) ++l;  /* Get to non-blank */
  774.       if (l[0] == 'e' && l[1] == 'n' && l[2] == 'd') {
  775.       /*
  776.          Check to make sure it isn't an ENDIF or some other variable name
  777.       */
  778.          l += 3;
  779.          if (*l == '\n' || *l == '#') {
  780.             Braces = 0;
  781.             bp = 1;
  782.          }
  783.       }
  784.     break;
  785.     case LISP:
  786.     /*
  787.        Lisp requires the context to be preserved, hence Braces stays 0 (a
  788.        lie) and LooksLikeLisp() handles everything.
  789.     */
  790.     break;
  791.    }
  792.    return(bp);
  793. }
  794.  
  795. PutString (str, len, line, newline)
  796. char *str;
  797. int len;
  798. int line;
  799. int newline;
  800. {
  801. /*
  802.    All lines of program text that are written through here are checked for
  803.    tabs.  This should include all parts of each line of code (to keep the
  804.    internal column counter straight).
  805. */
  806.    static char *lbuf = (char *)0;
  807.    static int   lbuflen = 0;
  808.    static char spaces[] = {"                                 "};
  809.    static int col = 0;
  810.    static int front=1;
  811.    int i, need;
  812.    register char *d, *s, c;
  813.  
  814.    if (len == -1) len = strlen (str);
  815.  
  816.    need =(len+OffsetValue+20)<<1;  /* mult by 2, so that \ work for postcript
  817.  */
  818.    if( need > lbuflen ) {
  819.       if( lbuf ) free(lbuf);
  820.       lbuflen = need;
  821.       lbuf = (char *)malloc(lbuflen);
  822.       if( ! lbuf ) {
  823.      fprintf( stderr, "MALLOC error, insufficient memory\n" );
  824.      exit(1);
  825.       }
  826.    }
  827.    *lbuf = '\0';
  828.  
  829.    if( OffsetValue && front ) sprintf (lbuf, "%.*s", OffsetValue, spaces);
  830.    if( line  && front ) {
  831.       sprintf (lbuf, "%6d  ", FileLineNumber);
  832.    }
  833.    front = 0;
  834.    col = strlen(lbuf);
  835.    d = lbuf+col;
  836.  
  837.    s = str;
  838.    for (i=0; i < len; ++i, ++s) {
  839.       c = *s;
  840.       switch (c) {
  841.       case '\t':
  842.          do {
  843.         *d++ = ' ';
  844.          } while (col++ % TabWidth != (TabWidth - 1));
  845.       break;
  846.       case '\b':
  847.      *d++ = c;
  848.          if (col > 0) --col;
  849.       break;
  850.       case '\n':
  851.          col = 0;
  852.      if( s[1] ) *d++ = '\n';
  853.      break;
  854.       case '\f':
  855.          col = 0;
  856.      *d++ = c;
  857.       break;
  858.  
  859.       case '(':
  860.       case ')':
  861.      if( Printer == POSTSCRIPT ) {
  862.         *d++ = '\\';
  863.         *d++ = c;
  864.         break;
  865.      }
  866.      /*FALLTHROUGH*/
  867.  
  868.       default:
  869.      *d++ = c;
  870.          ++col;
  871.       }
  872.    }
  873.    *d++ = '\0';
  874.  
  875.    switch(Printer) {
  876.       case POSTSCRIPT:
  877.          printf( "(%s) %s\n", lbuf, newline ? "s":"sn" );
  878.      break;
  879.  
  880.       default:
  881.      printf( "%s", lbuf );
  882.      if(newline) putchar('\n');
  883.      break;
  884.    }
  885.    if( newline ) front = 1;
  886. }
  887.  
  888. PutBold (bstr, len, flag)
  889. char *bstr;
  890. int len, flag;
  891. /*-
  892.    Put ``str'' bolded on stdout (possibly using ^H's).  (This test a flag
  893.    to support other types of bolding options.)  Assume ``str'' is ``len''
  894.    characters long, unless ``len'' == -1, then use strlen for the length
  895.    of ``str''.  If ``flag'' is 0 then print here without calling PutString
  896.    (in other words, don't pass it on as part of a code line for tab
  897.    column counting/expansion).
  898.  
  899.    When working with escape sequences, don't call PutString to print out the
  900.    escape sequences themselves.  Otherwise the tab expansion will be off.
  901.    (PutString adjusts column counter for \b's, but it doesn't need to know
  902.    about escape sequences.)
  903. */
  904. {
  905.    int str_flag = 0;
  906.    char *str;
  907.  
  908.    if( len == -1 ) {
  909.       len = strlen(bstr);
  910.       str = bstr;
  911.    }
  912.    else {
  913.       str_flag = 1;
  914.       str = malloc(len+2);
  915.       strncpy(str, bstr, len);
  916.    }
  917.  
  918.    switch (Printer) {
  919.    case DUMB:
  920.       PutString (str, len, NumberFlag, 0);  /* Just give up--printer is too
  921.  dumb */
  922.    break;
  923.    case ANSI:
  924.    case LN03:
  925.       printf ("\033[1m");
  926.       PutString (str, len, NumberFlag, 0);
  927.       printf ("\033[22m");
  928.    break;
  929.    case NECP5200:
  930.       printf ("\033E");
  931.       PutString (str, len, NumberFlag, 0);
  932.       printf ("\033F");
  933.    break;
  934.    case POSTSCRIPT:
  935.       printf( "(%s) sb\n", str );
  936.       break;
  937.  
  938.    case BACKSPACE:
  939.    {
  940.       int j, k;
  941.       char *buf, *s;
  942.  
  943.       s = buf = (char *)malloc(len*3+10);
  944.       for( k=0; *str; ) {
  945.      *s++ = *str;
  946.      *s++ = '\b';
  947.      *s++ = *str++;
  948.      k += 3;
  949.       }
  950.       *s++ = '\0';
  951.       /*
  952.       strcpy( s, str );
  953.       s += len;
  954.       for(k=0; k<len; k++ ) *s++='\b';
  955.       strcpy( s, str );
  956.       */
  957.  
  958.       if (flag)
  959.          PutString (buf, k, NumberFlag, 0);
  960.       else
  961.          printf(buf);
  962.       free(buf);
  963.    }
  964.    break;
  965.  
  966.    default:
  967.       fprintf (stderr, "Unknown printer type in PutBold\n");
  968.       exit (1);
  969.    }
  970.    if( str_flag ) free(str);
  971. }
  972.  
  973. char *
  974. EndComment(p)
  975. register char *p;
  976. {
  977.    register char c;
  978.  
  979.    /*
  980.          * Always return pointer to last non-null char looked at.
  981.          */
  982.    while( c = *p++ )
  983.       if( c == '*' && *p == '/' )
  984.       {
  985.          InComment = 0;
  986.          return(p);
  987.       }
  988.    return(p-2);
  989. }
  990. /* cpr got too big to ship as mail so I'm splitting it here... jdc */
  991. #include "cpr.c2"
  992.